package me.xiaoyan.android.tuition.utils;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import me.xiaoyan.android.net.HttpDatas;
import me.xiaoyan.android.net.HttpManager;
import me.xiaoyan.android.net.HttpManager.HTTPMETHOD;
import me.xiaoyan.android.net.RequestHeader;
import me.xiaoyan.android.widget.DataBackListener;
import me.xiaoyan.android.widget.RandomUtils;
import me.xiaoyan.json.JSONArray;
import me.xiaoyan.json.JSONException;
import me.xiaoyan.json.JSONObject;

import org.apache.http.conn.ConnectTimeoutException;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.util.encoders.Hex;

import android.accounts.NetworkErrorException;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class SESHttp {
	private static String DESKEY = "";
	private final static String INNER_PWD = "SESPWDIS";
	private final static String TEST_STR = "this is a test"; // 握手信息

	private static String APIHOST = "http://cdsnake.oicp.net:5964/sesServer/";
	private static String URL_PUBKEY = APIHOST + "ses/getPublicKey";
	private static String UP_SESSION_KEY = APIHOST + "ses/uploadSessionKey";
	private final static String CLIENTID = "10012";
	private final static String SESSION_DATA_KEY = "SES_SESSION";

	/**
	 * 发送请求
	 * 
	 * @param api
	 * @param action
	 * @param param
	 */
	public static void sendRequest(final String action,
			final Map<String, Object> param, final DataBackListener dbl) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					if (!AppManager.getInstance().hasAppDatas(SESSION_DATA_KEY)) {
						getPublicKey();
					}
					if (AppManager.getInstance().hasAppDatas(SESSION_DATA_KEY)) {
						String resp = sendRequest(
								APIHOST + action,
								param,
								AppManager.getInstance()
										.getAppDatas(SESSION_DATA_KEY)
										.toString());
						Handler handler = AppManager.getInstance().getHandler();
						Message msg = handler.obtainMessage(0, dbl);
						Bundle data = new Bundle();
						data.putString("source", resp);
						msg.setData(data);
						handler.sendMessage(msg);
					}
				} catch (TuitionException e) {
					Handler handler = AppManager.getInstance().getHandler();
					Message msg = handler.obtainMessage(e.getErrorCode(), dbl);
					Bundle data = new Bundle();
					data.putString("source", e.getMessage());
					msg.setData(data);
					handler.sendMessage(msg);
					e.printStackTrace();
				}
			}
		}).start();

	}

	private static String sendRequest(String url, Map<String, Object> param,
			String session) throws TuitionException {

		param.put("clientId", CLIENTID);
		String postData = new JSONObject(param).toString();

		System.out.println(url);
		System.out.println("POST:" + postData);

		String scode = MD5(postData + INNER_PWD + session);

		byte[] des_key = DESKEY.getBytes();
		byte[] pds = Hex.encode(ThreeDESUtil.encryptDESede(des_key,
				postData.getBytes()));
		postData = new String(pds);

		List<RequestHeader> header = new ArrayList<RequestHeader>();

		header.add(new RequestHeader("sessionid", session));
		header.add(new RequestHeader("scode", scode));
		header.add(new RequestHeader("Content-Type", "application/json"));

		HttpDatas data = null;
		try {
			data = HttpManager.openUrl(url, postData, header);
		}catch (ConnectTimeoutException e) { // 连接超时
			throw new TuitionException(CodeUtil.ERROR_TIMEOUT, e);
		} catch (NetworkErrorException e) {
			throw new TuitionException(CodeUtil.ERROR_NETWORK, e);
		} catch (Exception e) {
			throw new TuitionException(CodeUtil.ERROR_DEFAULT, e);
		}
		if (data.getHeader("sslcode") != null
				&& data.getHeader("sslcode").equalsIgnoreCase("1")) {
			byte[] endes = Hex.decode(data.getContent());
			byte[] dedes = ThreeDESUtil.decryptDESede(des_key, endes);
			return new String(dedes);
		}
		return data.getContent();
	}

	public static void getPublicKey() throws TuitionException {
		synchronized (SESHttp.class) {
			List<RequestHeader> header = new ArrayList<RequestHeader>();
			header.add(new RequestHeader("Content-Type", "application/json"));
			HttpDatas data;
			try {
				data = HttpManager.openUrl(URL_PUBKEY, HTTPMETHOD.POST, null,
						header);
			} catch (ConnectTimeoutException e) { // 连接超时
				throw new TuitionException(CodeUtil.ERROR_TIMEOUT, e);
			} catch (NetworkErrorException e) {
				throw new TuitionException(CodeUtil.ERROR_NETWORK, e);
			} catch (Exception e) {
				throw new TuitionException(CodeUtil.ERROR_DEFAULT, e);
			}
			JSONObject json;
			try {
				json = parseJson(data.getContent()).getJSONObject(0);
			} catch (JSONException e) {
				throw new TuitionException(CodeUtil.ERROR_PARSE_DATA, e);
			} catch (Exception e) {
				throw new TuitionException(CodeUtil.ERROR_DEFAULT, e);
			}
			String pubkey = json.getString("public"); // 公约指数
			String modulus = json.getString("modulus"); // 公共模
			DESKEY = RandomUtils.genRandomPassword(24, false, true);
			uploadSession(pubkey, data.getHeader("sessionid"), modulus);
		}
	}

	private static void uploadSession(String pubkey, String session,
			String modulus) throws TuitionException {
		String scode = MD5(TEST_STR + INNER_PWD + session);// 生成安全验效码
		RSAKeyParameters RSApubKey = new RSAKeyParameters(true, new BigInteger(
				modulus), new BigInteger("65537"));
		String sessionKey = "";
		try {
			sessionKey = new String(Hex.encode(RSAUtil.RSAEncrypt(new String(
					Hex.encode(DESKEY.getBytes())), RSApubKey)));
		} catch (Exception e) {
			throw new TuitionException("加密失败");
		}// 生成会话密钥

		byte[] des_key = DESKEY.getBytes();

		String handShakeMsg = new String(Hex.encode(ThreeDESUtil.encryptDESede(
				des_key, TEST_STR.getBytes()))); // 握手消息

		List<RequestHeader> header = new ArrayList<RequestHeader>();

		header.add(new RequestHeader("sessionid", session));
		header.add(new RequestHeader("scode", scode));

		Map<String, Object> param = new HashMap<String, Object>();
		param.put("sessionKey", sessionKey);
		param.put("handShakeMsg", handShakeMsg);

		HttpDatas data = null;
		try {
			data = HttpManager.openUrl(UP_SESSION_KEY, param, header);
		} catch (ConnectTimeoutException e) { // 连接超时
			throw new TuitionException(CodeUtil.ERROR_TIMEOUT, e);
		} catch (NetworkErrorException e) {
			throw new TuitionException(CodeUtil.ERROR_NETWORK, e);
		} catch (Exception e) {
			throw new TuitionException(CodeUtil.ERROR_DEFAULT, e);
		}
		System.out.println(data.getContent());

		JSONObject json = null;
		try {
			json = parseJson(data.getContent()).getJSONObject(0);
		} catch (JSONException e) {
			throw new TuitionException(CodeUtil.ERROR_PARSE_DATA, e);
		} catch (Exception e) {
			throw new TuitionException(CodeUtil.ERROR_DEFAULT, e);
		}

		String handShakeMsg_resp = json.getString("handShakeMsg");
		byte[] endes = Hex.decode(handShakeMsg_resp);
		String decode = new String(ThreeDESUtil.decryptDESede(des_key, endes));
		if (!decode.equals(session)) {
			throw new TuitionException("安全驗證失敗");
		}
		AppManager.getInstance().setAppDatas(SESSION_DATA_KEY, session);
	}

	public static JSONArray parseJson(String source) throws Exception {
		JSONObject jsonObject = new JSONObject(source);
		int code = jsonObject.getInt("code");
		if (code != 0) {
			throw new Exception(jsonObject.getString("msg")
					+ String.format("(%s)", code));
		}
		return jsonObject.getJSONArray("data");
	}

	public static String MD5(String s) {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F' };
		try {
			byte[] btInput = s.getBytes();
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			mdInst.update(btInput);
			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			int j = md.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

}
